package shop.up.product.service.impl;

import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import shop.up.product.service.TestService;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * TODO {@link TestServiceImpl}
 *
 * @author Kevin
 * @date 2022/7/11
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * redisson 实现分布式锁
     */
    @Override
    public void testLock() {
        // 获取锁
        RLock rLock = redissonClient.getLock("lock");
        // 不设置过期时间，则默认使用看门狗机制，默认有一个30的ttl，会自动续期
        rLock.lock();

        // 处理业务逻辑
        // 查询redis中的num值
        String value = (String)this.redisTemplate.opsForValue().get("num");
        // 没有该值return
        if (StringUtils.isBlank(value)){
            return ;
        }
        // 有值就转成成int
        int num = Integer.parseInt(value);
        // 把redis中的num值+1
        this.redisTemplate.opsForValue().set("num", String.valueOf(++num));

        // 释放锁
        rLock.unlock();
    }

    /**
     * 读
     * @return
     */
    @Override
    public String readLock() {
        // 初始化读写锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readwriteLock");
        RLock rLock = readWriteLock.readLock(); // 获取读锁

        rLock.lock(10, TimeUnit.SECONDS); // 加10s锁

        String msg = this.redisTemplate.opsForValue().get("msg");

        //rLock.unlock(); // 解锁
        return msg;
    }

    /**
     * 写
     * @return
     */
    @Override
    public String writeLock() {
        // 初始化读写锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("readwriteLock");
        RLock rLock = readWriteLock.writeLock(); // 获取写锁

        rLock.lock(10, TimeUnit.SECONDS); // 加10s锁

        this.redisTemplate.opsForValue().set("msg", UUID.randomUUID().toString());

        //rLock.unlock(); // 解锁
        return "成功写入了内容。。。。。。";
    }

    /**
     * redis 实现分布式锁
     */
    // @Override
    // public void testLock() {
    //     String uuid = UUID.randomUUID().toString();
    //     // 获取锁
    //     Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 1, TimeUnit.SECONDS);
    //     if (lock) { // true 获取到锁
    //         // 处理业务逻辑
    //         // 查询redis中的num值
    //         String value = (String)this.redisTemplate.opsForValue().get("num");
    //         // 没有该值return
    //         if (StringUtils.isBlank(value)){
    //             return ;
    //         }
    //         // 有值就转成成int
    //         int num = Integer.parseInt(value);
    //         // 把redis中的num值+1
    //         this.redisTemplate.opsForValue().set("num", String.valueOf(++num));
    //
    //         // uuid确保只删除自己的锁，删除不具备原子性
    //         // String redisUUID = redisTemplate.opsForValue().get("lock");
    //         // if (uuid.equals(redisUUID)) {
    //         //     // 释放锁
    //         //     redisTemplate.delete("lock");
    //         // }
    //
    //         // LUA脚本来保证删除锁原子性
    //         //  定义一个lua 脚本
    //         String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    //         //  准备执行lua 脚本
    //         DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
    //         //  将lua脚本放入DefaultRedisScript 对象中
    //         redisScript.setScriptText(script);
    //         //  设置DefaultRedisScript 这个对象的泛型
    //         redisScript.setResultType(Long.class);
    //         //  执行删除
    //         redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
    //
    //     } else {
    //         try {
    //             Thread.sleep(100);
    //             // 自旋
    //             testLock();
    //         } catch (InterruptedException e) {
    //             e.printStackTrace();
    //         }
    //     }
    // }

}
